#include <stdio.h>

#include "IOI2C.h"

#define TRUE 1
#define FALSE 0

static uint8_t IIC_Start(void);
static void IIC_Stop(void);
static void IIC_Send_Byte(uint8_t txd);
static uint8_t IIC_Read_Byte(void);
static uint8_t IIC_Wait_Ack(void);
static void IIC_Ack(void);
static void IIC_NAck(void);

/* Private functions ---------------------------------------------------------*/

static void IIC_delay(void)
{
	uint16_t i=3;//针对72Mhz主频运行速率的延时
	while(i)
	{
		i--;
	}
}

void IIC_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	/* Configure PD0 and PD2 in output pushpull mode */
	GPIO_InitStructure.GPIO_Pin = VL53_SCL_Pin | VL53_SDA_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
}

/**************************实现函数********************************************
*函数原型:		void IIC_Start(void)
*功　　能:		产生IIC起始信号
*******************************************************************************/
/***
   从函数结构看出，先是把SDA和SCL电平都拉高，延时后将SDA电平拉低，使其出现下降沿，
   再延时后SCL电平也置低。函数严格遵循了起始条件产生的时序。
void i2c_Start(void)
{
    I2C_SDA_1();
    I2C_SCL_1();
    Delay();
    I2C_SDA_0();
    Delay();
    I2C_SCL_0();
    Delay();
}
 ***/

static uint8_t IIC_Start(void)
{
	SDA_H;
	SCL_H;
	IIC_delay();
	if(!SDA_read)
	{
		printf("[IIC_Start] -> SDA_H error!\r\n");
		return FALSE;
	}
	SDA_L;
	IIC_delay();
	if(SDA_read)
	{
		printf("[IIC_Start] -> SDA_L error!\r\n");
		return FALSE;
	}
	SDA_L;
	IIC_delay();
	return TRUE;
}

/**************************实现函数********************************************
*函数原型:		void IIC_Stop(void)
*功　　能:	    //产生IIC停止信号
*******************************************************************************/
/***
   在SCL高电平时，SDA出现一个上升沿，即产生停止信号。
void i2c_Stop(void)
{
    I2C_SDA_0();
    I2C_SCL_1();
    Delay();
    I2C_SDA_1();
}
 ***/

static void IIC_Stop(void)
{
	SCL_L;
	IIC_delay();
	SDA_L;
	IIC_delay();
	SCL_H;
	IIC_delay();
	SDA_H;
	IIC_delay();
}

/**************************实现函数********************************************
*函数原型:		uint8_t IIC_Wait_Ack(void)
*功　　能:	    等待应答信号到来
//返回值：1，接收应答失败
//        0，接收应答成功
*******************************************************************************/
static uint8_t IIC_Wait_Ack(void)
{
	SCL_L;
	IIC_delay();
	SDA_H;
	IIC_delay();
	SCL_H;
	IIC_delay();
	if(SDA_read)
	{
		printf("[IIC_Wait_Ack] -> SDA_L error!\r\n");
		SCL_L;
		IIC_delay();
		return FALSE;
	}
	SCL_L;
	IIC_delay();
	return TRUE;
}

/**************************实现函数********************************************
*函数原型:		void IIC_Ack(void)
*功　　能:	    产生ACK应答
*******************************************************************************/
/***
 void i2c_Ack(void)
{
    I2C_SDA_0();
    Delay();
    I2C_SCL_1();
    Delay();
    I2C_SCL_0();
    Delay();
    I2C_SDA_1();	// CPU释放SDA
}
   ***/

static void IIC_Ack(void)
{
	SCL_L;
	IIC_delay();
	SDA_L;
	IIC_delay();
	SCL_H;
	IIC_delay();
	SCL_L;
	IIC_delay();
}

/**************************实现函数********************************************
*函数原型:		void IIC_NAck(void)
*功　　能:	    产生NACK应答
*******************************************************************************/
/***
   void i2c_NAck(void)
{
    I2C_SDA_1();
    Delay();
    I2C_SCL_1();
    Delay();
    I2C_SCL_0();
    Delay();
}
 ***/
static void IIC_NAck(void)
{
	SCL_L;
	IIC_delay();
	SDA_H;
	IIC_delay();
	SCL_H;
	IIC_delay();
	SCL_L;
	IIC_delay();
}

/**************************实现函数********************************************
*函数原型:		void IIC_Send_Byte(uint8_t txd)
*功　　能:	    IIC发送一个字节
*******************************************************************************/
static void IIC_Send_Byte(uint8_t SendByte)
{
	uint8_t i=8;
	while(i--)
	{
		SCL_L;
		IIC_delay();
		if(SendByte&0x80)
			SDA_H;
		else
			SDA_L;
		SendByte<<=1;
		IIC_delay();
		SCL_H;
		IIC_delay();
	}
	SCL_L;
}

/**************************实现函数********************************************
*函数原型:		uint8_t IIC_Read_Byte(unsigned char ack)
*功　　能:	    //读1串字节，ack=1时，发送ACK，ack=0，发送nACK
*******************************************************************************/
static unsigned char IIC_Read_Byte(void)
{
	uint8_t i=8;
	uint8_t ReceiveByte=0;

	SDA_H;
	while(i--)
	{
		ReceiveByte<<=1;
		SCL_L;
		IIC_delay();
		SCL_H;
		IIC_delay();
		if(SDA_read)
		{
			ReceiveByte|=0x01;
		}
	}
	SCL_L;
	return ReceiveByte;
}

/**************************实现函数********************************************
*函数原型:		unsigned char IIC_ReadOneByte(unsigned char I2C_Addr,unsigned char addr)
*功　　能:	    读取指定设备 指定寄存器的一个值
输入	I2C_Addr  目标设备地址
		addr	   寄存器地址
返回   读出来的值
*******************************************************************************/
uint8_t IIC_ReadOneByte(uint8_t SlaveAddress,uint16_t REG_Address,uint8_t* data)
{
	if(!IIC_Start())
		return FALSE;
	IIC_Send_Byte(SlaveAddress);
	if(!IIC_Wait_Ack())
	{
		IIC_Stop();
		return FALSE;
	}
	IIC_Send_Byte((uint8_t) REG_Address>>8);
	IIC_Wait_Ack();
	IIC_Send_Byte((uint8_t) REG_Address & 0x00ff);
	IIC_Wait_Ack();
	IIC_Start();
	IIC_Send_Byte(SlaveAddress+1);
	IIC_Wait_Ack();

	*data= IIC_Read_Byte();
	IIC_NAck();
	IIC_Stop();
	return TRUE;
}


/**************************实现函数********************************************
*函数原型:		uint8_t IICreadBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data)
*功　　能:	    读取指定设备 指定寄存器的 length个值
输入	dev  目标设备地址
		reg	  寄存器地址
		length 要读的字节数
		*data  读出的数据将要存放的指针
返回   读出来的字节数量
*******************************************************************************/
uint8_t IICreadBytes(uint8_t SlaveAddress,uint16_t REG_Address,uint8_t len,uint8_t *data)
{
	uint8_t i = 0;
	if(!IIC_Start())
		return FALSE;
	IIC_Send_Byte(SlaveAddress);
	if(!IIC_Wait_Ack())
	{
		IIC_Stop();
		return FALSE;
	}
	IIC_Send_Byte((uint8_t) REG_Address>>8);
	IIC_Wait_Ack();
	IIC_Send_Byte(REG_Address&0x00ff);
	IIC_Wait_Ack();
	IIC_Start();
	IIC_Send_Byte(SlaveAddress+1);
	IIC_Wait_Ack();

	for(i = 0; i<len; i++)
	{
		if(i != (len -1))
		{
			data[i]= IIC_Read_Byte();
			IIC_Ack();
		}
		else
		{
			data[i]= IIC_Read_Byte();
			IIC_NAck();
		}
	}
	IIC_Stop();
	return len;
}

/**************************实现函数********************************************
*函数原型:		uint8_t IICwriteBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t* data)
*功　　能:	    将多个字节写入指定设备 指定寄存器
输入	dev  目标设备地址
		reg	  寄存器地址
		length 要写的字节数
		*data  将要写的数据的首地址
返回   返回写入长度
*******************************************************************************/
uint8_t IICwriteBytes(uint8_t dev, uint16_t reg, uint16_t length, uint8_t* data)
{

	uint8_t count = 0;
	IIC_Start();
	IIC_Send_Byte(dev);
	IIC_Wait_Ack();
	IIC_Send_Byte(reg>>8);
	IIC_Wait_Ack();
	IIC_Send_Byte(reg & 0x00ff);
	IIC_Wait_Ack();
	for(count=0; count<length; count++)
	{
		IIC_Send_Byte(data[count]);
		IIC_Wait_Ack();
	}
	IIC_Stop();

	return length; //status == 0;
}


/**************************实现函数********************************************
*函数原型:		unsigned char IICwriteByte(unsigned char dev, unsigned char reg, unsigned char data)
*功　　能:	    写入指定设备 指定寄存器一个字节
输入	dev  目标设备地址
		reg	   寄存器地址
		data  将要写入的字节
返回   1
*******************************************************************************/
uint8_t IICwriteByte(uint8_t dev, uint16_t reg, uint8_t data)
{
	return IICwriteBytes(dev, reg, 1, &data);
}


/**************************实现函数********************************************
*函数原型:		uint8_t IICwriteBit(uint8_t dev, uint8_t reg, uint8_t bitNum, uint8_t data)
*功　　能:	    读 修改 写 指定设备 指定寄存器一个字节 中的1个位
输入	dev  目标设备地址
		reg	   寄存器地址
		bitNum  要修改目标字节的bitNum位
		data  为0 时，目标位将被清0 否则将被置位
返回   成功 为1
 		失败为0
*******************************************************************************/
uint8_t IICwriteBit(uint8_t dev, uint16_t reg, uint8_t bitNum, uint8_t data)
{
	uint8_t b;
	IIC_ReadOneByte(dev, reg, &b);
	b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
	return IICwriteByte(dev, reg, b);
}

//------------------End of File----------------------------
